home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / Delphi 3.0 / DATA.Z / nstois.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1997-01-29  |  24.1 KB  |  825 lines

  1. unit NSToIS;
  2.  
  3. interface
  4.  
  5. uses SysUtils, Windows, Classes, ISAPI2, NSAPI, SyncObjs;
  6.  
  7. type
  8.   TISAPIApplicationList = class;
  9.  
  10.   TISAPIApplication = class
  11.   private
  12.     FModule: THandle;
  13.     FFileName: string;
  14.     FVersionInfo: THSE_VERSION_INFO;
  15.     FOwner: TISAPIApplicationList;
  16.   public
  17.     GetExtensionVersion: TGetExtensionVersion;
  18.     HTTPExtensionProc: THTTPExtensionProc;
  19.     TerminateExtension: TTerminateExtension;
  20.     constructor Create(AOWner: TISAPIApplicationList; const AFileName: string);
  21.     destructor Destroy; override;
  22.  
  23.     procedure Load;
  24.     procedure Unload(Ask: Boolean);
  25.  
  26.     property VersionInfo: THSE_VERSION_INFO read FVersionInfo;
  27.   end;
  28.  
  29.   EISAPIException = class(Exception);
  30.  
  31.   TISAPISession = class
  32.   private
  33.     { ISAPI Interface }
  34.     FECB: TEXTENSION_CONTROL_BLOCK;
  35.     FISAPIApplication: TISAPIApplication;
  36.     FPathTranslated: string;
  37.     { NSAPI Interface }
  38.     Fpb: PPblock;
  39.     Fsn: PSession;
  40.     Frq: PRequest;
  41.     Fenv: PPCharArray;
  42.     { HSE_REQ_DONE_WITH_SESSION event }
  43.     FEvent: TEvent; 
  44.  
  45.     { ISAPI Service functions }
  46.     function GetServerVariable(VariableName: PChar; Buffer: Pointer; var Size: DWORD): Boolean;
  47.     function WriteClient(Buffer: Pointer; var Bytes: DWORD): Boolean;
  48.     function ReadClient(Buffer: Pointer; var Size: DWORD): Boolean;
  49.     function ServerSupportFunction(HSERequest: DWORD; Buffer: Pointer;
  50.       Size: LPDWORD; DataType: LPDWORD): Boolean;
  51.   public
  52.     constructor Create(pb: PPblock; sn: PSession; rq: PRequest;
  53.       ISAPIApplication: TISAPIApplication);
  54.     destructor Destroy; override;
  55.     procedure ProcessExtension;
  56.   end;
  57.  
  58.   TISAPIApplicationList = class
  59.   private
  60.     FList: TList;
  61.     FCriticalSection: TCriticalSection;
  62.     FLogfd: SYS_FILE;
  63.     procedure AddApplication(ISAPIApplication: TISAPIApplication);
  64.     procedure ClearApplications;
  65.     function FindApplication(const AFileName: string): TISAPIApplication;
  66.     procedure RemoveApplication(ISAPIApplication: TISAPIApplication);
  67.   public
  68.     constructor Create;
  69.     destructor Destroy; override;
  70.     function LoadApplication(const AFileName: string): TISAPIApplication;
  71.     function InitLog(pb: PPblock; sn: PSession; rq: Prequest): Integer;
  72.     procedure LogMessage(const Fmt: string; Params: array of const);
  73. {    function NewSession(ISAPIApplication: TISAPIApplication; pb: PPBlock;
  74.       sn: PSession; rq: PRequest): TISAPISession;}
  75.   end;
  76.  
  77. var
  78.   ISAPIApplicationList: TISAPIApplicationList = nil;
  79.  
  80. procedure LogMessage(const Fmt: string; Params: array of const);
  81. function UnixPathToDosPath(const Path: string): string;
  82. function DosPathToUnixPath(const Path: string): string;
  83. procedure InitISAPIApplicationList;
  84. procedure DoneISAPIAPplicationList;
  85.  
  86. implementation
  87.  
  88. function TranslateChar(const Str: string; FromChar, ToChar: Char): string;
  89. var
  90.   I: Integer;
  91. begin
  92.   Result := Str;
  93.   for I := 1 to Length(Result) do
  94.     if Result[I] = FromChar then
  95.       Result[I] := ToChar
  96.     else if Result[I] = '?' then Break;
  97. end;
  98.  
  99. function UnixPathToDosPath(const Path: string): string;
  100. begin
  101.   Result := TranslateChar(Path, '/', '\');
  102. end;
  103.  
  104. function DosPathToUnixPath(const Path: string): string;
  105. begin
  106.   Result := TranslateChar(Path, '\', '/');
  107. end;
  108.  
  109. procedure LogMessage(const Fmt: string; Params: array of const);
  110. begin
  111.   ISAPIApplicationList.LogMessage(Fmt, Params);
  112. end;
  113.  
  114. { TISAPIApplication }
  115.  
  116. constructor TISAPIApplication.Create(AOwner: TISAPIApplicationList;
  117.   const AFileName: string);
  118. begin
  119.   FFileName := AFileName;
  120.   FOwner := AOwner;
  121.   FOwner.AddApplication(Self);
  122.   Load;
  123. end;
  124.  
  125. destructor TISAPIApplication.Destroy;
  126. begin
  127.   Unload(False);
  128.   FOwner.RemoveApplication(Self);
  129.   inherited Destroy;
  130. end;
  131.  
  132. procedure TISAPIApplication.Load;
  133. var
  134.   ErrorMode: Integer;
  135. begin
  136.   ErrorMode := SetErrorMode(SEM_NOOPENFILEERRORBOX);
  137.   try
  138.     FModule := LoadLibrary(PChar(FFileName));
  139.     if FModule > 32 then
  140.     begin
  141.       @GetExtensionVersion := GetProcAddress(FModule, 'GetExtensionVersion');
  142.       @HTTPExtensionProc := GetProcAddress(FModule, 'HttpExtensionProc');
  143.       @TerminateExtension := GetProcAddress(FModule, 'TerminateExtension');
  144.       if not Assigned(GetExtensionVersion) or not Assigned(HTTPExtensionProc) then
  145.         raise EISAPIException.CreateFmt('Invalid ISAPI application: %s', [FFileName]);
  146.       if GetExtensionVersion(FVersionInfo) then
  147.       begin
  148.         LogMessage('%s: Version: $%.8x'#13#10, [FFileName, FVersionInfo.dwExtensionVersion]);
  149.         if (HiWord(FVersionInfo.dwExtensionVersion) <> $0001) and
  150.           (HiWord(FVersionInfo.dwExtensionVersion) <> $0002) then
  151.           raise EISAPIException.CreateFmt('Unsupported ISAPI Application version: %.8x',
  152.             [FVersionInfo.dwExtensionVersion]);
  153.       end else
  154.         raise EISAPIException.CreateFmt('Call to GetExtensionVersion FAILED. Error Code: %d',
  155.           [GetLastError]);
  156.     end else
  157.       raise EISAPIException.CreateFmt('Error loading ISAPI Application: %s', [FFileName]);
  158.   finally
  159.     SetErrorMode(ErrorMode);
  160.   end;
  161. end;
  162.  
  163. procedure TISAPIApplication.Unload(Ask: Boolean);
  164. const
  165.   HSE_TERM: array[Boolean] of DWORD = (HSE_TERM_ADVISORY_UNLOAD, HSE_TERM_MUST_UNLOAD);
  166. var
  167.   CanUnload: Boolean;
  168. begin
  169.   if FModule > 32 then
  170.   begin
  171.     CanUnload := True;
  172.     if Assigned(TerminateExtension) then
  173.       CanUnload := not Ask or TerminateExtension(HSE_TERM[Ask]);
  174.     if CanUnload and FreeLibrary(FModule) then
  175.       FModule := 0;
  176.   end;
  177. end;
  178.  
  179. function GetServerVariableProc(ConnID: HConn; VariableName: PChar;
  180.   Buffer: Pointer; var Size: DWORD): BOOL; stdcall;
  181. begin
  182.   if ConnID <> 0 then
  183.     Result := TISAPISession(ConnID).GetServerVariable(VariableName, Buffer, Size)
  184.   else
  185.   begin
  186.     Result := False;
  187.     SetLastError(ERROR_INVALID_PARAMETER);
  188.   end;
  189. end;
  190.  
  191. function WriteClientProc(ConnID: HConn; Buffer: Pointer; var Bytes: DWORD;
  192.   dwReserved: DWORD): BOOL; stdcall;
  193. begin
  194.   if ConnID <> 0 then
  195.     Result := TISAPISession(ConnID).WriteClient(Buffer, Bytes)
  196.   else
  197.   begin
  198.     Result := False;
  199.     SetLastError(ERROR_INVALID_PARAMETER);
  200.   end;
  201. end;
  202.  
  203. function ReadClientProc(ConnID: HConn; Buffer: Pointer;
  204.   var Size: DWORD): BOOL; stdcall;
  205. begin
  206.   if ConnID <> 0 then
  207.     Result := TISAPISession(ConnID).ReadClient(Buffer, Size)
  208.   else
  209.   begin
  210.     Result := False;
  211.     SetLastError(ERROR_INVALID_PARAMETER);
  212.   end;
  213. end;
  214.  
  215. function ServerSupportProc(ConnID: HConn; HSERequest: DWORD; Buffer: Pointer;
  216.   Size: LPDWORD; DataType: LPDWORD): BOOL; stdcall;
  217. begin
  218.   if ConnID <> 0 then
  219.     Result := TISAPISession(ConnID).ServerSupportFunction(HSERequest, Buffer,
  220.       Size, DataType)
  221.   else
  222.   begin
  223.     Result := False;
  224.     SetLastError(ERROR_INVALID_PARAMETER);
  225.   end;
  226. end;
  227.  
  228. function MakeValid(Str: PChar): PChar;
  229. begin
  230.   if Str = nil then
  231.     Result := ''
  232.   else Result := Str;
  233. end;
  234.  
  235. const
  236.   DocumentMoved =
  237.     '<head><title>Document moved</title></head>' +
  238.     '<body><h1>Object Moved</h1>' +
  239.     'This document may be found <a HREF="%s">here</a></body>'#13#10;
  240.  
  241. // Diagnostic purposes only... Do not resource these strings    
  242. function GetObjectConfig(os: PHttpdObjSet): string;
  243. var
  244.   obj: PHttpdObject;
  245.   dt: PDtable;
  246.   dir: PDirective;
  247.   I, J, K: Integer;
  248. begin
  249.   Result := Format('os: $%p'#13#10, [os]);
  250.   try
  251.     if os <> nil then
  252.     begin
  253.       K := 0;
  254.       obj := PPointerList(os.obj)^[K];
  255.       Result := Format('%sobj: $%p'#13#10, [Result, obj]);
  256.       if obj <> nil then
  257.       begin
  258.         while obj <> nil do
  259.         begin
  260.           Result := Format('%sobj.name: $%p'#13#10, [Result, obj.name]);
  261.           Result := Format('%sRoot Object: %s (%s)'#13#10, [Result, 'default',
  262.             NSstr2String(pblock_pblock2str(obj.name, nil))]);
  263.           dt := obj.dt;
  264.           Result := Format('%sobj.dt: $%p'#13#10'obj.nd: %d'#13#10, [Result, dt, obj.nd]);
  265.           for I := 0 to obj.nd - 1 do
  266.           begin
  267.             dir := dt.inst;
  268.             Result := Format('%sdt.inst: $%p'#13#10'dt.ni: %d'#13#10, [Result, dir, dt.ni]);
  269.             for J := 0 to dt.ni - 1 do
  270.             begin
  271.               if dir <> nil then
  272.               begin
  273.                 if dir.param <> nil then
  274.                   Result := Format('%s  Param: %s'#13#10, [Result,
  275.                     NSstr2String(pblock_pblock2str(dir.param, nil))])
  276.                 else Result := Format('%s  Param:'#13#10, [Result]);
  277.                 if dir.client <> nil then
  278.                   Result := Format('%s  Client: %s'#13#10, [Result,
  279.                     NSstr2String(pblock_pblock2str(dir.client, nil))])
  280.                 else Result := Format('%s  Client:'#13#10, [Result]);
  281.               end;
  282.               Inc(dir);
  283.             end;
  284.             Inc(dt);
  285.           end;
  286.           Inc(K);
  287.           obj := PPointerList(os.obj)^[K];
  288.         end;
  289.       end else Result := 'root_object not found';
  290.     end else Result := 'std_os Objset not found';
  291.   except
  292.     on E: Exception do
  293.       Result := Format('%sException %s: %s'#13#10, [Result, E.ClassName, E.Message]);
  294.   end;
  295. end;
  296.  
  297. { TISAPISession }
  298.  
  299. constructor TISAPISession.Create(pb: PPblock; sn: PSession; rq: PRequest;
  300.   ISAPIApplication: TISAPIApplication);
  301. var
  302.   Temp: PChar;
  303. begin
  304.   Fpb := pb;
  305.   Fsn := sn;
  306.   Frq := rq;
  307.   FISAPIApplication := ISAPIApplication;
  308.   FEvent := TSimpleEvent.Create;
  309.   with FECB do
  310.   begin
  311.     cbSize := SizeOf(FECB);
  312.     dwVersion := MAKELONG(HSE_VERSION_MINOR, HSE_VERSION_MAJOR);
  313.     ConnID := THandle(Self);
  314.     lpszMethod := MakeValid(pblock_findval('method', rq.reqpb));
  315.     lpszQueryString := MakeValid(pblock_findval('query', rq.reqpb));
  316.     lpszPathInfo := MakeValid(pblock_findval('path-info', rq.vars));
  317.     FPathTranslated := UnixPathToDosPath(NSstr2String(
  318.       pblock_findval('path-translated', rq.vars)));
  319.     lpszPathTranslated := PChar(FPathTranslated);
  320.     lpszContentType := MakeValid(pblock_findval('content-type', rq.headers));
  321.     Temp := pblock_findval('content-length', rq.headers);
  322.     try
  323.       cbTotalBytes := StrToIntDef(MakeValid(Temp), 0);
  324.     finally
  325.       system_free(Temp);
  326.     end;
  327.     with Fsn.inbuf^ do
  328.     begin
  329.       while (inbuf[pos] in [#13,#10]) and (pos < cursize) do Inc(pos);
  330.       cbAvailable := cursize - pos;
  331.       if cbTotalBytes < cbAvailable then
  332.         cbTotalBytes := cbAvailable;
  333.       GetMem(lpbData, cbAvailable);
  334.       Move(inbuf[pos], lpbData^, cbAvailable);
  335.     end;
  336.     GetServerVariable := GetServerVariableProc;
  337.     WriteClient := WriteClientProc;
  338.     ReadClient := ReadClientProc;
  339.     ServerSupportFunction := ServerSupportProc;
  340.   end;
  341. end;
  342.  
  343. destructor TISAPISession.Destroy;
  344.  
  345.   procedure FreeStr(Str: PChar);
  346.   begin
  347.     if (Str <> nil) and (Str^ <> #0) then
  348.       system_free(Str);
  349.   end;
  350.  
  351. begin
  352.   with FECB do
  353.   begin
  354.     FreeStr(lpszMethod);
  355.     FreeStr(lpszQueryString);
  356.     FreeStr(lpszPathInfo);
  357.     FreeStr(lpszContentType);
  358.     FreeMem(lpbData);
  359.   end;
  360.   if Fenv <> nil then util_env_free(Fenv);
  361.   FEvent.Free;
  362.   inherited Destroy;
  363. end;
  364.  
  365. function TISAPISession.GetServerVariable(VariableName: PChar; Buffer: Pointer;
  366.   var Size: DWORD): Boolean;
  367. var
  368.   HeaderName: string;
  369.   HeaderValue: PChar;
  370.  
  371.   procedure InitEnv;
  372.   var
  373.     Value: PChar;
  374.  
  375.     procedure AddToEnv(var Env: PPCharArray; Name, Value: PChar);
  376.     var
  377.       Pos: Integer;
  378.     begin
  379.       Env := util_env_create(Env, 1, Pos);
  380.       Env[Pos] := util_env_str(Name, Value);
  381.       Env[Pos+1] := nil;
  382.     end;
  383.  
  384.   begin
  385.     if Fenv = nil then
  386.     begin
  387.       Fenv := http_hdrs2env(Frq.headers);
  388.       Value := pblock_findval('content-length', Frq.headers);
  389.       try
  390.         if Value <> nil then
  391.           AddToEnv(Fenv, 'HTTP_CONTENT_LENGTH', Value);
  392.       finally
  393.         system_free(Value);
  394.       end;
  395.       Value := pblock_findval('content-type', Frq.headers);
  396.       try
  397.         if Value <> nil then
  398.           AddToEnv(Fenv, 'HTTP_CONTENT_TYPE', Value);
  399.       finally
  400.         system_free(Value);
  401.       end;
  402.     end;
  403.   end;
  404.  
  405.   procedure CopyValue(Value: PChar; var Result: Boolean);
  406.   begin
  407.     Result := False;
  408.     PChar(Buffer)[0] := #0;
  409.     if Value <> nil then
  410.     begin
  411.       StrLCopy(Buffer, Value, Size);
  412.       if Size < StrLen(Value) then
  413.         SetLastError(ERROR_INSUFFICIENT_BUFFER)
  414.       else Result := True;
  415.       Size := StrLen(Value) + 1;
  416.     end else SetLastError(ERROR_NO_DATA);
  417.   end;
  418.  
  419.   function AllHeaders: string;
  420.   var
  421.     P: PPCharArray;
  422.     I: Integer;
  423.   begin
  424.     InitEnv;
  425.     P := Fenv;
  426.     Result := '';
  427.     I := 0;
  428.     while P^[I] <> nil do
  429.     begin
  430.       Result := Format('%s%s'#13#10, [Result, TranslateChar(P^[I], '=', ':')]);
  431.       Inc(I);
  432.     end;
  433.   end;
  434.  
  435. begin
  436.   // Check if this is a request for an HTTP header
  437.   if VariableName = nil then VariableName := 'BAD';
  438.   LogMessage('GetServerVariable(%s, $%p, %d)'#13#10, [VariableName, Buffer, Size]);
  439.   HeaderValue := nil;
  440.   HeaderName := VariableName;
  441.   if shexp_casecmp(VariableName, 'HTTP_*') = 0 then
  442.   begin
  443.     InitEnv;
  444.     CopyValue(util_env_find(Fenv, VariableName), Result);
  445.     Exit;
  446.   end else
  447.   begin
  448.     if CompareText('CONTENT_LENGTH', HeaderName) = 0 then
  449.       HeaderValue := pblock_findval('content-length', Frq.headers)
  450.     else if CompareText('CONTENT_TYPE', HeaderName) = 0 then
  451.       HeaderValue := pblock_findval('content-type', Frq.headers)
  452.     else if CompareText('PATH_INFO', HeaderName) = 0 then
  453.       HeaderValue := pblock_findval('path-info', Frq.vars)
  454.     else if CompareText('PATH_TRANSLATED', HeaderName) = 0 then
  455.       HeaderValue := pblock_findval('path-translated', Frq.vars)
  456.     else if CompareText('QUERY_STRING', HeaderName) = 0 then
  457.       HeaderValue := pblock_findval('query', Frq.reqpb)
  458.     else if CompareText('REMOTE_ADDR', HeaderName) = 0 then
  459.       HeaderValue := pblock_findval('ip', Fsn.client)
  460.     else if CompareText('REMOTE_HOST', HeaderName) = 0 then
  461.       HeaderValue := session_dns(Fsn)
  462.     else if CompareText('REQUEST_METHOD', HeaderName) = 0 then
  463.       HeaderValue := pblock_findval('method', Frq.reqpb)
  464.     else if CompareText('SCRIPT_NAME', HeaderName) = 0 then
  465.       HeaderValue := pblock_findval('uri', Frq.reqpb)
  466.     else if CompareText('SERVER_NAME', HeaderName) = 0 then
  467.       HeaderValue := system_version
  468.     else if CompareText('ALL_HTTP', HeaderName) = 0 then
  469.     begin
  470.       CopyValue(PChar(AllHeaders), Result);
  471.       Exit;
  472.     end else if CompareText('SERVER_PORT', HeaderName) = 0 then
  473.     begin
  474.       CopyValue(PChar(IntToStr(conf_getglobals.Vport)), Result);
  475.       Exit
  476.     end else if CompareText('SERVER_PROTOCOL', HeaderName) = 0 then
  477.       HeaderValue := pblock_findval('protocol', Frq.reqpb)
  478.     else if CompareText('URL', HeaderName) = 0 then
  479.       HeaderValue := pblock_findval('uri', Frq.reqpb)
  480.     else if CompareText('OBJECT_CONFIG', HeaderName) = 0 then
  481.     begin
  482.       CopyValue(PChar(Format('<pre>%s</pre><br>', [GetObjectConfig(Frq.os)])), Result);
  483.       Exit;
  484.     end else
  485.     begin
  486.       Result := False;
  487.       SetLastError(ERROR_INVALID_INDEX);
  488.     end;
  489.   end;
  490.   try
  491.     CopyValue(HeaderValue, Result);
  492.   finally
  493.     system_free(HeaderValue);
  494.   end;
  495. end;
  496.  
  497. function TISAPISession.WriteClient(Buffer: Pointer; var Bytes: DWORD): Boolean;
  498. var
  499.   nWritten: Integer;
  500. begin
  501.   LogMessage('WriteClient($%p, %d)'#13#10, [Buffer, Bytes]);
  502.   nWritten := net_write(Fsn.csd, Buffer, Bytes);
  503.   Result := not (nWritten < Bytes) and not (nWritten = IO_ERROR);
  504.   Bytes := nWritten;
  505. end;
  506.  
  507. function TISAPISession.ReadClient(Buffer: Pointer; var Size: DWORD): Boolean;
  508. var
  509.   nBuf, nRemaining: Integer;
  510. begin
  511.   LogMessage('ReadClient($%p, %d)'#13#10, [Buffer, Size]);
  512.   nRemaining := Size;
  513.   while nRemaining > 0 do
  514.   begin
  515.     with Fsn.inbuf^ do
  516.       if pos < cursize then
  517.       begin
  518.         nBuf := cursize - pos;
  519.         if nBuf > Size then nBuf := Size;
  520.         Move(inbuf[pos], Buffer, nBuf);
  521.         Inc(pos, nBuf);
  522.         Dec(nRemaining, nBuf);
  523.         Inc(Integer(Buffer), nBuf);
  524.       end else
  525.       begin
  526.         nBuf := net_read(Fsn.csd, Buffer, nRemaining, NET_READ_TIMEOUT);
  527.         if nBuf = IO_ERROR then Break;
  528.         Dec(nRemaining, nBuf);
  529.       end;
  530.   end;
  531.   if nRemaining = 0 then
  532.     Result := True
  533.   else Result := False;
  534.   Size := Size - nRemaining;
  535. end;
  536.  
  537. function TISAPISession.ServerSupportFunction(HSERequest: DWORD; Buffer: Pointer;
  538.   Size: LPDWORD; DataType: LPDWORD): Boolean;
  539. var
  540.   Content: PChar;
  541.   ContentLen: Integer;
  542.   ContentStr: string;
  543.  
  544.   // This function will parse out any ISAPI application supplied headers and
  545.   // place them into the appropriate parameter block.
  546.   function SkipHeaders(Content: PChar): PChar;
  547.   var
  548.     T: array[0..REQ_MAX_LINE - 1] of Char;
  549.     pb: PPblock;
  550.     NetBuf: TNetBuf;
  551.   begin
  552.     if Content <> nil then
  553.     begin
  554.       pb := pblock_create(10);
  555.       try
  556.         FillChar(NetBuf, SizeOf(NetBuf), 0);
  557.         with NetBuf do
  558.         begin
  559.           cursize := StrLen(Content);
  560.           maxSize := curSize;
  561.           inbuf := Content;
  562.         end;
  563.         http_scan_headers(nil, @NetBuf, T, pb);
  564.         pblock_copy(pb, Frq.srvhdrs);
  565.         // Skip past the headers if present
  566.         Inc(Content, NetBuf.pos);
  567.         Result := Content;
  568.       finally
  569.         pblock_free(pb);
  570.       end;
  571.     end else Result := Content;
  572.   end;
  573.  
  574.   procedure SetStatus(StatusStr: PChar);
  575.   var
  576.     StatusCode: Integer;
  577.     I: Integer;
  578.   begin
  579.     if StatusStr = nil then
  580.       StatusCode := PROTOCOL_OK
  581.     else
  582.     begin
  583.       StatusCode := StrToIntDef(Copy(StatusStr, 1, 3), PROTOCOL_OK);
  584.       for I := 0 to 3 do
  585.       begin
  586.         if StatusStr[0] = #0 then Break;
  587.         Inc(StatusStr);
  588.       end;
  589.     end;
  590.     http_status(Fsn, Frq, StatusCode, StatusStr);
  591.   end;
  592.  
  593. begin
  594.   case HSERequest of
  595.     HSE_REQ_SEND_RESPONSE_HEADER:
  596.       begin
  597.         if DataType <> nil then
  598.           Content := PChar(Datatype)
  599.         else Content := '#0';
  600.         if Size <> nil then
  601.           LogMessage('ServerSupportFunction(HSE_REQ_SEND_RESPONSE_HEADER' +
  602.             ', $%p, %d, %s)'#13#10, [Buffer, Size^, Content])
  603.         else LogMessage('ServerSupportFunction(HSE_REQ_SEND_RESPONSE_HEADER' +
  604.             ', $%p, nil, %s)'#13#10, [Buffer, Content]);
  605.         SetStatus(PChar(Buffer));
  606.         param_free(pblock_remove('content-type', Frq.srvhdrs));
  607.         param_free(pblock_remove('content-length', Frq.srvhdrs));
  608.         Content := SkipHeaders(PChar(DataType));
  609.         ContentLen := StrLen(Content);
  610.         Result := True;
  611.         if http_start_response(Fsn, Frq) <> REQ_NOACTION then
  612.         begin
  613.           if (Content <> nil) and (Content[0] <> #0) then
  614.             if net_write(Fsn.csd, Content, ContentLen) < ContentLen then
  615.               Result := False;
  616.         end else Result := False;
  617.       end;
  618.     HSE_REQ_SEND_URL_REDIRECT_RESP:
  619.       begin
  620.         if Size <> nil then
  621.           LogMessage('ServerSupportFunction(HSE_REQ_SEND_URL_REDIRECT_RESP' +
  622.             ', %s, %d)'#13#10, [PChar(Buffer), Size^])
  623.         else LogMessage('ServerSupportFunction(HSE_REQ_SEND_URL_REDIRECT_RESP' +
  624.             ', %s, nil)'#13#10, [PChar(Buffer)]);
  625.         http_status(Fsn, Frq, PROTOCOL_REDIRECT, 'Object moved');
  626.         param_free(pblock_remove('content-type', Frq.srvhdrs));
  627.         param_free(pblock_remove('content-length', Frq.srvhdrs));
  628.         if Buffer <> nil then
  629.         begin
  630.           pblock_nvinsert('Location', PChar(Buffer), Frq.srvhdrs);
  631.           ContentStr := Format(DocumentMoved, [PChar(Buffer)]);
  632.           ContentLen := Length(ContentStr);
  633.           pblock_nvinsert('content-type', 'text/html', Frq.srvhdrs);
  634.           pblock_nninsert('content-length', ContentLen, Frq.srvhdrs);
  635.           Result := True;
  636.           if http_start_response(Fsn, Frq) <> REQ_NOACTION then
  637.           begin
  638.             if net_write(Fsn.csd, PChar(ContentStr), ContentLen) < ContentLen then
  639.               Result := False;
  640.           end else Result := False;
  641.         end else raise EISAPIException.Create('Invalid Redirect parameter');
  642.       end;
  643.     HSE_REQ_SEND_URL:
  644.       begin
  645.         Result := False;
  646.       end;
  647.     HSE_REQ_MAP_URL_TO_PATH:
  648.       begin
  649.         Result := True;
  650.         Content := request_translate_uri(Buffer, Fsn);
  651.         if Content <> nil then
  652.         try
  653.           StrPLCopy(Buffer, Content, Size^);
  654.           if Size^ < StrLen(Content) + 1 then
  655.           begin
  656.             Result := False;
  657.             SetLastError(ERROR_INSUFFICIENT_BUFFER);
  658.           end;
  659.         finally
  660.           system_free(Content);
  661.         end else
  662.         begin
  663.           Result := False;
  664.           SetLastError(ERROR_NO_DATA);
  665.         end;
  666.       end;
  667.     HSE_REQ_DONE_WITH_SESSION:
  668.       begin
  669.         FEvent.SetEvent;
  670.         Result := True;
  671.       end;
  672.   else
  673.     Result := False;
  674.   end;
  675. end;
  676.  
  677. procedure TISAPISession.ProcessExtension;
  678. begin
  679.   LogMessage('ProcessExtension -- Application: %s'#13#10, [FISAPIApplication.FFileName]);
  680.   if Assigned(FISAPIApplication.HTTPExtensionProc) then
  681.     case FISAPIApplication.HTTPExtensionProc(FECB) of
  682.       HSE_STATUS_ERROR: raise EISAPIException.Create('ISAPI Application Error');
  683.       HSE_STATUS_PENDING: FEvent.WaitFor(INFINITE);
  684.     end;
  685. end;
  686.  
  687. { TISAPIApplicationList }
  688.  
  689. constructor TISAPIApplicationList.Create;
  690. begin
  691.   FList := TList.Create;
  692.   FCriticalSection := TCriticalSection.Create;
  693.   FLogfd := SYS_ERROR_FD;
  694. end;
  695.  
  696. destructor TISAPIApplicationList.Destroy;
  697. begin
  698.   ClearApplications;
  699.   FList.Free;
  700.   FCriticalSection.Free;
  701.   if FLogfd <> SYS_ERROR_FD then
  702.     system_fclose(FLogfd);
  703.   inherited Destroy;
  704. end;
  705.  
  706. procedure TISAPIApplicationList.AddApplication(ISAPIApplication: TISAPIApplication);
  707. begin
  708.   FCriticalSection.Enter;
  709.   try
  710.     if FList.IndexOf(ISAPIApplication) = -1 then
  711.       FList.Add(ISAPIApplication);
  712.   finally
  713.     FCriticalSection.Leave;
  714.   end;
  715. end;
  716.  
  717. procedure TISAPIApplicationList.ClearApplications;
  718. var
  719.   ISAPIApplication: TISAPIApplication;
  720. begin
  721.   FCriticalSection.Enter;
  722.   try
  723.     while FList.Count > 0 do
  724.     begin
  725.       ISAPIApplication := FList.Last;
  726.       FList.Remove(ISAPIApplication);
  727.       ISAPIApplication.Free;
  728.     end;
  729.   finally
  730.     FCriticalSection.Leave;
  731.   end;
  732. end;
  733.  
  734. function TISAPIApplicationList.FindApplication(const AFileName: string): TISAPIApplication;
  735. var
  736.   I: Integer;
  737. begin
  738.   FCriticalSection.Enter;
  739.   try
  740.     for I := 0 to FList.Count - 1 do
  741.     begin
  742.       Result := FList[I];
  743.       with Result do
  744.         if CompareText(AFileName, FFileName) = 0 then
  745.           Exit;
  746.     end;
  747.     Result := nil;
  748.   finally
  749.     FCriticalSection.Leave;
  750.   end;
  751. end;
  752.  
  753. function TISAPIApplicationList.InitLog(pb: PPblock; sn: PSession; rq: Prequest): Integer;
  754. var
  755.   fn: Pchar;
  756. begin
  757.   fn := pblock_findval('file', pb);
  758.   try
  759.  
  760.     if fn = nil then
  761.     begin
  762.       pblock_nvinsert('error', 'TISAPIApplicationList: please supply a file name', pb);
  763.       Result := REQ_ABORTED;
  764.       Exit;
  765.     end;
  766.  
  767.     FLogfd := system_fopenWA(fn);
  768.     if FLogfd = SYS_ERROR_FD then
  769.     begin
  770.       pblock_nvinsert('error', 'TISAPIApplicationList: please supply a file name', pb);
  771.       Result := REQ_ABORTED;
  772.       Exit;
  773.     end;
  774.   finally
  775.     system_free(fn);
  776.   end;
  777.   {* Close log file when server is restarted *}
  778.   Result := REQ_PROCEED;
  779. end;
  780.  
  781. function TISAPIApplicationList.LoadApplication(const AFileName: string): TISAPIApplication;
  782. begin
  783.   Result := FindApplication(AFileName);
  784.   if Result = nil then
  785.     Result := TISAPIApplication.Create(Self, AFileName);
  786. end;
  787.  
  788. procedure TISAPIApplicationList.LogMessage(const Fmt: string; Params: array of const);
  789. var
  790.   logmsg: string;
  791.   len: Integer;
  792. begin
  793.   if FLogfd <> SYS_ERROR_FD then
  794.   begin
  795.     FmtStr(logmsg, Fmt, Params);
  796.     len := Length(logmsg);
  797.     system_fwrite_atomic(FLogfd, PChar(logmsg), len);
  798.   end;
  799. end;
  800.  
  801. procedure TISAPIApplicationList.RemoveApplication(ISAPIApplication: TISAPIApplication);
  802. begin
  803.   FCriticalSection.Enter;
  804.   try
  805.     if FList.IndexOf(ISAPIApplication) > -1 then
  806.       FList.Remove(ISAPIApplication);
  807.   finally
  808.     FCriticalSection.Leave;
  809.   end;
  810. end;
  811.  
  812. procedure InitISAPIApplicationList;
  813. begin
  814.   if ISAPIApplicationList = nil then
  815.     ISAPIApplicationList := TISAPIApplicationList.Create;
  816. end;
  817.  
  818. procedure DoneISAPIAPplicationList;
  819. begin
  820.   ISAPIApplicationList.Free;
  821.   ISAPIApplicationList := nil;
  822. end;
  823.  
  824. end.
  825.